Skip to main content

One37ID Mobile SDK Overview & Setup

Before we dive into the code, let’s make sure you have everything you need to get started. Here’s a quick checklist:

  • VS Code or any code editor of your choice.
  • Node.js and NPM: For package management and running your development environment.
  • Xcode or Android Studio: For compilation depending on the platform you’re targeting, iOS or Android.
  • React Native: Our platform of choice for building cross-platform mobile apps.
  • One37ID SDK: The star of the show, allowing you to manage secure credentials.

Compatibility

The One37ID SDK works with:

  • Expo: Versions 50 and 51.
  • React Native CLI: Requires additional configurations for integrating Expo modules.

Installation


Installation for Expo Projects

Step 1: Adjust Project Setup

  • Use Bare Workflow when creating a new Expo project.

Step 2: Configure .npmrc

Create a .npmrc file in the root directory:

@one37id:registry=https://gitlab.com/api/v4/projects/51752488/packages/npm/
//gitlab.com/api/v4/projects/51752488/packages/npm/:authToken=[AUTH_TOKEN]

Replace [AUTH_TOKEN] with your GitLab access token.

Step 3: Install SDK and Dependencies

  • Install the One37ID SDK:

    yarn add @one37id/mobile-js-sdk@^0.2412.2001
  • Install Non-Expo Packages:

    yarn add @bacons/text-decoder@^0.0.0 \
    @digitalbazaar/security-context@^1.0.1 \
    @ethersproject/shims@^5.7.0 \
    @sphereon/isomorphic-webcrypto@2.4.1-unstable.0 \
    @sphereon/pex-models@^2.2.2 \
    @sphereon/react-native-argon2@^2.0.9 \
    assert@^1.1.1 \
    buffer@^4.9.1 \
    fast-text-encoding@^1.0.6 \
    msrcrypto@^1.5.8 \
    path-browserify@^0.0.0 \
    process@^0.11.0 \
    react@18.2.0 \
    @veramo/data-store@4.2.0 \
    @veramo/did-comm@4.2.0 \
    ajv@^8.12.0 \
    ajv-formats@^2.1.1 \
    react-native@0.74.5 \
    react-native-device-info@^14.0.1 \
    react-native-dotenv@^3.4.11 \
    react-native-fs@^2.20.0 \
    react-native-get-random-values@^1.11.0 \
    react-native-level-fs@^3.0.1 \
    react-native-modal@^13.0.1 \
    react-native-os@^1.2.6 \
    react-native-quick-crypto@^0.7.6 \
    react-native-screens@3.31.1 \
    react-native-securerandom@^1.0.1 \
    react-native-url-polyfill@^2.0.0 \
    react-native-vector-icons@^10.2.0 \
    readable-stream@^1.0.33 \
    rn-nodeify@^10.3.0 \
    reflect-metadata@^0.1.13 \
    stream-browserify@^3.0.0 \
    text-encoding@^0.7.0 \
    text-encoding-polyfill@^0.6.7 \
    vm-browserify@^0.0.4
  • Install Expo Packages:

    npx expo install expo-crypto
    npx expo install expo-file-system
    npx expo install expo-fs
    npx expo install expo-sqlite

Step 4: Add Configurations to package.json

Add the following entries to your package.json to ensure compatibility and resolve dependency conflicts:

Updated package.json
"scripts": {
"postinstall": "patch-package && rn-nodeify --install os,fs,path,assert,buffer,process,stream,vm --hack"
},
"resolutions": {
"@sphereon/isomorphic-argon2": "1.0.1",
"@veramo/credential-ld": "4.2.0",
"@veramo/did-resolver": "4.2.0",
"@veramo/utils": "4.2.0",
"@mattrglobal/bbs-signatures": "npm:@animo-id/react-native-bbs-signatures@^0.1.0",
"@sphereon/ssi-types": "0.22.0",
"@sphereon/ssi-sdk-ext.kms-local": "0.18.1",
"@sphereon/pex": "3.3.1",
"@sphereon/pex-models": "2.2.2",
"@types/react": "~18.2.45",
"**/@types/react": "~18.2.45",
"**/expo-random": "~13.6.0",
"ajv": "^8.12.0",
"react-native-permissions": "^3.8.0",
"expo-fs/expo-file-system": "~15.2.2",
"expo-file-system": "^16.0.9",
"**/jsonld": "link:./node_modules/@digitalcredentials/jsonld",
"**/crypto": "link:./node_modules/@sphereon/isomorphic-webcrypto",
"**/isomorphic-webcrypto": "link:./node_modules/@sphereon/isomorphic-webcrypto",
"security-context": "link:./node_modules/@digitalbazaar/security-context",
"@transmute/web-crypto-key-pair/@peculiar/webcrypto": "^1.1.6",
"@peculiar/webcrypto": "1.4.5",
"typeorm": "0.3.20",
"**/typeorm": "0.3.20"
},
Additional Steps
  1. Add a patches folder in your root directory: Download Here.
  2. Run the following command:
    yarn postinstall
    yarn install
Why Are We Doing This?
  1. Script Automation: The postinstall script automates the process of applying necessary patches and configuring polyfills for Node.js modules like os, fs, path, and crypto. These modules are not natively supported in React Native, and this step is crucial for enabling the SDK's functionality in mobile environments.

  2. Dependency Resolutions: The resolutions field addresses version conflicts between dependencies by enforcing specific versions. This ensures consistency and avoids issues caused by mismatched or incompatible nested dependencies.

  3. Patches Folder: The patches fix issues in third-party dependencies, allowing you to use the SDK without waiting for official updates. This ensures the SDK operates smoothly in your project.

Step 5: Configure metro.config.js

Add the following configuration:

// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require("expo/metro-config");
const { mergeConfig } = require("metro-config");
const defaultSourceExts =
require("metro-config/src/defaults/defaults").sourceExts;
const defaultAssetExts =
require("metro-config/src/defaults/defaults").assetExts;

const defaultConfig = getDefaultConfig(__dirname);

/** @type {import('expo/metro-config').MetroConfig} */
const config = {
transformer: {
assetPlugins: ["expo-asset/tools/hashAssetFiles"],
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
minifierConfig: {
keep_classnames: true, // enable to fix typeorm
keep_fnames: true, // enable to fix typeorm
mangle: {
toplevel: false,
keep_classnames: true, // enable to fix typeorm
keep_fnames: true, // enable to fix typeorm
},
output: {
ascii_only: true,
quote_style: 3,
wrap_iife: true,
},
sourceMap: {
includeSources: false,
},
toplevel: false,
compress: {
reduce_funcs: false,
},
},
},
resolver: {
assetExts: [...defaultAssetExts.filter((ext) => ext !== "svg"), "tflite"],
sourceExts: [...defaultSourceExts, "cjs", "json", "mjs"],
extraNodeModules: {
stream: require.resolve("readable-stream"),
crypto: require.resolve("@sphereon/isomorphic-webcrypto"),
fs: require.resolve("expo-fs"),
path: require.resolve("path-browserify"),
os: require.resolve("react-native-os"),
},
},
};

module.exports = mergeConfig(defaultConfig, config);

Step 6: Configure index.js

Modify your index.js file:

import './shim';
import 'reflect-metadata';
import 'react-native-get-random-values';
import "react-native-url-polyfill/auto";
import '@ethersproject/shims';
import 'fast-text-encoding';
import 'path-browserify';

Step 7: Modify shim.js

import { install as installCrypto } from "react-native-quick-crypto";

if (typeof __dirname === "undefined") global.__dirname = "/";
if (typeof __filename === "undefined") global.__filename = "";
if (typeof process === "undefined") {
global.process = require("process");
} else {
const bProcess = require("process");
for (var p in bProcess) {
if (!(p in process)) {
process[p] = bProcess[p];
}
}
}
import "@bacons/text-decoder/install";

global.TextEncoder = require("text-encoding").TextEncoder;

process.browser = false;
if (typeof Buffer === "undefined") global.Buffer = require("buffer").Buffer;

// global.location = global.location || { port: 80 }
const isDev = typeof __DEV__ === "boolean" && __DEV__;

if (typeof process.env["NODE_ENV"] !== "string") {
// process.env['NODE_ENV'] = isDev !== false ? 'development' : 'production';
}
if (typeof localStorage !== "undefined") {
localStorage.debug = isDev ? "*" : "";
}

installCrypto();
if (!global.window.crypto) {
global.window.crypto = global.crypto;
}
if (typeof self !== "undefined") {
self.crypto = global.crypto;
}

// If using the crypto shim, uncomment the following line to ensure
// crypto is loaded first, so it can populate global.crypto
// require('crypto')

Restart Metro Server

npx expo start -c

Additional Commands

If you encounter issues, try these commands:

cd android
./gradlew clean
cd ..
cd ios
pod install
cd ..
yarn cache clean
npx expo install --check

Final Steps

Run the project:

  • For Android: npx expo run:android
  • For iOS: npx expo run:ios

Installation for React Native CLI Projects

Step 1: Install Expo Modules

Install Expo modules to link packages correctly:

npx install-expo-modules

Step 2: Configure .npmrc

Create a .npmrc file in the root directory:

@one37id:registry=https://gitlab.com/api/v4/projects/51752488/packages/npm/
//gitlab.com/api/v4/projects/51752488/packages/npm/:authToken=[AUTH_TOKEN]

Replace [AUTH_TOKEN] with your GitLab access token.

Step 3: Install SDK and Dependencies

  • Install the One37ID SDK:

    yarn add @one37id/mobile-js-sdk@^0.2412.2001
  • Install Non-Expo Packages:

    yarn add @bacons/text-decoder@^0.0.0 \
    @digitalbazaar/security-context@^1.0.1 \
    @ethersproject/shims@^5.7.0 \
    @sphereon/isomorphic-webcrypto@2.4.1-unstable.0 \
    @sphereon/pex-models@^2.2.2 \
    @sphereon/react-native-argon2@^2.0.9 \
    assert@^1.1.1 \
    buffer@^4.9.1 \
    fast-text-encoding@^1.0.6 \
    msrcrypto@^1.5.8 \
    path-browserify@^0.0.0 \
    process@^0.11.0 \
    react@18.2.0 \
    @veramo/data-store@4.2.0 \
    @veramo/did-comm@4.2.0 \
    ajv@^8.12.0 \
    ajv-formats@^2.1.1 \
    react-native@0.74.5 \
    react-native-device-info@^14.0.1 \
    react-native-dotenv@^3.4.11 \
    react-native-fs@^2.20.0 \
    react-native-get-random-values@^1.11.0 \
    react-native-level-fs@^3.0.1 \
    react-native-modal@^13.0.1 \
    react-native-os@^1.2.6 \
    react-native-quick-crypto@^0.7.6 \
    react-native-screens@3.31.1 \
    react-native-securerandom@^1.0.1 \
    react-native-url-polyfill@^2.0.0 \
    react-native-vector-icons@^10.2.0 \
    readable-stream@^1.0.33 \
    rn-nodeify@^10.3.0 \
    reflect-metadata@^0.1.13 \
    stream-browserify@^3.0.0 \
    text-encoding@^0.7.0 \
    text-encoding-polyfill@^0.6.7 \
    vm-browserify@^0.0.4
  • Install Expo Packages:

    npx expo install expo-crypto
    npx expo install expo-file-system
    npx expo install expo-fs
    npx expo install expo-sqlite

Step 4: Add Configurations to package.json

Add the following entries to your package.json to ensure compatibility and resolve dependency conflicts:

Updated package.json
"scripts": {
"postinstall": "patch-package && rn-nodeify --install os,fs,path,assert,buffer,process,stream,vm --hack"
},
"resolutions": {
"@sphereon/isomorphic-argon2": "1.0.1",
"@veramo/credential-ld": "4.2.0",
"@veramo/did-resolver": "4.2.0",
"@veramo/utils": "4.2.0",
"@mattrglobal/bbs-signatures": "npm:@animo-id/react-native-bbs-signatures@^0.1.0",
"@sphereon/ssi-types": "0.22.0",
"@sphereon/ssi-sdk-ext.kms-local": "0.18.1",
"@sphereon/pex": "3.3.1",
"@sphereon/pex-models": "2.2.2",
"@types/react": "~18.2.45",
"**/@types/react": "~18.2.45",
"**/expo-random": "~13.6.0",
"ajv": "^8.12.0",
"react-native-permissions": "^3.8.0",
"expo-fs/expo-file-system": "~15.2.2",
"expo-file-system": "^16.0.9",
"**/jsonld": "link:./node_modules/@digitalcredentials/jsonld",
"**/crypto": "link:./node_modules/@sphereon/isomorphic-webcrypto",
"**/isomorphic-webcrypto": "link:./node_modules/@sphereon/isomorphic-webcrypto",
"security-context": "link:./node_modules/@digitalbazaar/security-context",
"@transmute/web-crypto-key-pair/@peculiar/webcrypto": "^1.1.6",
"@peculiar/webcrypto": "1.4.5",
"typeorm": "0.3.20",
"**/typeorm": "0.3.20"
},
Additional Steps
  1. Add a patches folder in your root directory: Download Here.
  2. Run the following command:
    yarn install
    yarn postinstall
Why Are We Doing This?
  1. Script Automation: The postinstall script automates the process of applying necessary patches and configuring polyfills for Node.js modules like os, fs, path, and crypto. These modules are not natively supported in React Native, and this step is crucial for enabling the SDK's functionality in mobile environments.

  2. Dependency Resolutions: The resolutions field addresses version conflicts between dependencies by enforcing specific versions. This ensures consistency and avoids issues caused by mismatched or incompatible nested dependencies.

  3. Patches Folder: The patches fix issues in third-party dependencies, allowing you to use the SDK without waiting for official updates. This ensures the SDK operates smoothly in your project.

Step 5: Configure metro.config.js

Add the following configuration to ensure compatibility:

const { getDefaultConfig, mergeConfig } = require("@react-native/metro-config");
const { assetExts, sourceExts } = require("metro-config/src/defaults/defaults");

// Base Metro Config
const defaultConfig = getDefaultConfig(__dirname);

const config = {
transformer: {
// Enable Expo asset plugins
assetPlugins: ["expo-asset/tools/hashAssetFiles"],
// Metro transformer settings
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true, // Enables faster bundling
},
}),
minifierConfig: {
keep_classnames: true, // Fix for certain libraries like TypeORM
keep_fnames: true,
mangle: {
keep_classnames: true,
keep_fnames: true,
},
output: {
ascii_only: true,
quote_style: 3,
wrap_iife: true,
},
compress: {
reduce_funcs: false,
},
},
},
resolver: {
// Extend default asset and source extensions
assetExts: [...assetExts.filter((ext) => ext !== "svg")], // Removes svg to handle it via transformers if needed
sourceExts: [...sourceExts, "cjs", "mjs", "json"], // Additional extensions
extraNodeModules: {
// Polyfills for required node modules
stream: require.resolve("readable-stream"),
crypto: require.resolve("@sphereon/isomorphic-webcrypto"),
fs: require.resolve("expo-file-system"), // Maps to expo-file-system
path: require.resolve("path-browserify"),
os: require.resolve("react-native-os"),
},
},
};

module.exports = mergeConfig(defaultConfig, config);

Step 6: Configure index.js

Modify your index.js file:

import "./shim";
import "reflect-metadata";
import "react-native-url-polyfill/auto";
import "react-native-get-random-values";
import "@ethersproject/shims";
import "fast-text-encoding";
import "path-browserify";

Step 7: Modify shim.js

import { install as installCrypto } from "react-native-quick-crypto";

if (typeof __dirname === "undefined") global.__dirname = "/";
if (typeof __filename === "undefined") global.__filename = "";
if (typeof process === "undefined") {
global.process = require("process");
} else {
const bProcess = require("process");
for (var p in bProcess) {
if (!(p in process)) {
process[p] = bProcess[p];
}
}
}
import "@bacons/text-decoder/install";

global.TextEncoder = require("text-encoding").TextEncoder;

process.browser = false;
if (typeof Buffer === "undefined") global.Buffer = require("buffer").Buffer;

// global.location = global.location || { port: 80 }
const isDev = typeof __DEV__ === "boolean" && __DEV__;

if (typeof process.env["NODE_ENV"] !== "string") {
// process.env['NODE_ENV'] = isDev !== false ? 'development' : 'production';
}
if (typeof localStorage !== "undefined") {
localStorage.debug = isDev ? "*" : "";
}

installCrypto();
if (!global.window.crypto) {
global.window.crypto = global.crypto;
}
if (typeof self !== "undefined") {
self.crypto = global.crypto;
}

// If using the crypto shim, uncomment the following line to ensure
// crypto is loaded first, so it can populate global.crypto
// require('crypto')

Restart Metro Server

npx react-native start --reset-cache

Additional Commands

If you encounter issues, try these commands:

cd android
./gradlew clean
cd ..
cd ios
pod install
cd ..
yarn cache clean
npx expo install --check

Final Steps

Run the project:

  • For Android: npx react-native run-android
  • For iOS: npx react-native run-ios

Agent Initialization

Define async initialize agent function

Sample simple code

import {Agent, AgentConfig, HomeSetttings} from '@one37id/mobile-js-sdk';

let agentInstance: Agent | null = null;
let isAgentInitializing = false;

//import HomeSettings from @one37id/mobile-js-sdk
//In this case it will connect to one37id platform by default, replace the below info with your info
const agentInfo: HomeSetttings = {
linkedDomain: "https://137.dev-one37.id",
publicKeyHex:
"078e20665a3f939b0b7f9a8f2940ca04b552d9fe66885f3d0c3ab788fcead5d8",
isAllowUntrustConnections: false,
};
const DB_ENCRYPTION_KEY = '11139248cad1bd1a0fc4d9b75cd4d2990de535baf5caadfdf8d8f86664aa830c';
async function initializeAgent() {
const activityCallbackHandlers = {};
const callbackHandlers = {};
const eventHandlers = {};

if (!agentInstance) {
try {
if (isAgentInitializing) {
console.log("Agent is initializing");
return;
}
isAgentInitializing = true;

const firstName = "John"; // Replace with actual user first name
const lastName = "Doe"; // Replace with actual user last name

const agentConfig: AgentConfig = {
encryptionKey: DB_ENCRYPTION_KEY,
home: agentInfo,
webSocketSettings: {
idleTimeoutSeconds: 5 * 60,
scanIntervalSeconds: 5,
},
autoProcessIncomingMessages: false,
userInfo: {
name: firstName + " " + lastName,
},
callbackHandlers: callbackHandlers,
eventHandlers: eventHandlers,
activityCallbackHandlers: activityCallbackHandlers,
};
console.log("***waiting for agent to be created", agentConfig);
try {
console.log("Creating agent instance...");
agentInstance = await Agent.createInstance(agentConfig); //Here we create the agent instance
} catch (error) {
console.log("Error initializing agent", error);
isAgentInitializing = false;
return;
}

isAgentInitializing = false;
} catch (error) {
console.log("Error initializing agent2", error);
isAgentInitializing = false;
return;
// throw error;
}
}
return agentInstance;
}

export { initializeAgent, agentInstance };
tip

You can use this function anywhere in your app to access the agent instance and its services.

Example Code

import React, { useEffect } from "react";
import { StyleSheet, View, Text } from "react-native";
import { initializeAgent } from "../one37Agent"; //Modify as it should be
import { Agent } from "@one37id/mobile-js-sdk";

interface MainProps {}

const Main: React.FC<MainProps> = (props) => {
useEffect(() => {
const initAgent = async () => {
const agent = await initializeAgent();
if (agent) {
console.log("agent initialized", agent);
try {
const connections = await agent.contactManager.getList({
currentPage: 1,
rowsPerPage: 1000,
});
console.log("connections", connections);
} catch (e) {
console.log("error in getting connections", e);
}
} else {
console.log("agent not initialized");
}
};
initAgent();
}, []);

return (
<View style={styles.container}>
<Text style={styles.text}>Initialize Agent Screen</Text>
</View>
);
};

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
padding: 16,
},
text: {
fontSize: 24,
marginBottom: 20, // Space between text and button
},
});

export default Main;

Next Steps

Continue to the next section to build more features into your app with the One37ID SDK.

Additional Reading

Managers

Managers are classes responsible for managing various aspects of the One37ID SDK.

Before accessing any managers, you must first initialize the agent. After the agent is initialized, you can access the various managers.

To initialize the agent, use the following code:

const agent = await initializeAgent();

1. Contact Manager

The Contact Manager is responsible for managing all tasks related to connections.

2. Credential Manager

Credential Manager is a key component for managing verifiable credentials within the One37ID platform.

3. Alias Manager

The Alias Manager in the One37ID SDK is responsible for managing aliases, which are identifiers that can be used to represent entities (such as users or organizations) within the system.

4. Notification Manager

The Notification Manager is responsible for handling all tasks related to notifications within the system

X

Graph View